﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MineFlagger
{
    public partial class AIToolWindow : Form
    {
        IViewer view;
        GameBoard gameBoard;
        Random rnd;

        MainForm mainForm;

        public AIToolWindow()
        {
            InitializeComponent();
            chkBench.Checked = false;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.Left = mainForm.Right + 30;
            this.Top = mainForm.Top + 40;
        }

        public void Setup(MainForm mainForm, GameBoard gameBoard, IViewer view, Random rnd)
        {
            this.rnd = rnd;
            this.view = view;
            SetGameBoard(gameBoard);

            this.mainForm = mainForm;
            mainForm.Move += new EventHandler(mainForm_Move);

        }

        public void SetGameBoard(GameBoard gameBoard)
        {
            if (this.gameBoard != null)
                this.gameBoard.PropertyChanged -= new PropertyChangedEventHandler(gameBoard_PropertyChanged);

            this.gameBoard = gameBoard;
            this.gameBoard.PropertyChanged += new PropertyChangedEventHandler(gameBoard_PropertyChanged);

            setupAI();
        }

        #region Move 

        void mainForm_Move(object sender, EventArgs e)
        {
            this.Location = new Point(mainForm.Location.X + mainFormDx, mainForm.Location.Y + mainFormDy);
        }
        
        int mainFormDx;
        int mainFormDy;

        protected override void OnMove(EventArgs e)
        {
            mainFormDx = this.Location.X - mainForm.Location.X;
            mainFormDy = this.Location.Y - mainForm.Location.Y;
            
            base.OnMove(e);
        }

        #endregion




        void gameBoard_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (InvokeRequired)
                return;

            if (e.PropertyName == "PlayState")
            {
                if (gameBoard.PlayState == PlayState.New)
                {
                    setupAI();
                }
            }
        }

        void setupAI()
        {
            aiAnalysisControl2.SetUp(gameBoard, aiConfigControl1.AIConfig, view, rnd);
        }



        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                this.Hide();
            }

            base.OnFormClosing(e);
        }




        private void button3_Click(object sender, EventArgs e)
        {
            MinesweeperAI mineAI = new MinesweeperAI(gameBoard, view, aiConfigControl1.AIConfig, rnd);
            bool result = mineAI.AutoUncover();

            view.InvalidateDirtyCells();

            userChangedBoard();
        }
        private void userChangedBoard()
        {
            if (this.aiAnalysisControl2.AutoAnalyze)
            {
                aiAnalysisControl2.Analyze();
            }
        }


        private void chkBench_CheckedChanged(object sender, System.EventArgs e)
        {
            txtBenchGoal.Enabled = chkBench.Checked;
        }





        #region AI on Worker Thread

        Thread workerThread = null;

        MinesweeperAI curAI;
        private void button2_Click(object sender, System.EventArgs e)
        {
            if (workerThread != null && workerThread.IsAlive && !curAI.abort)
            {
                curAI.abort = true;
                button2.Enabled = false;

                while (workerThread.IsAlive)
                    Application.DoEvents();

                button2.Enabled = true;
                button2.Text = "Start AI";

            }
            else
            {
                curAI = null;

                workerThread = new Thread(new ThreadStart(this.DoWork_AI));

                button2.Text = "Abort";
                workerThread.Start();
            }
        }


        private delegate void UIBenchUpdate(string stats);
        void updatelbeBench(string stats)
        {
            if (InvokeRequired && !IsDisposed)
            {
                Invoke(new UIBenchUpdate(updatelbeBench), stats);
                return;
            }

            this.lbeBench.Text = stats;
        }



        void postDoWork_AI()
        {
            if (InvokeRequired && !IsDisposed)
            {
                Invoke(new UIWork(postDoWork_AI));
                return;
            }

            button2.Enabled = true;
            button2.Text = "Start AI";
        }

        public void DoWork_AI()
        {
            int wins = 0;
            int gamesToPlay = int.Parse(txtBenchGoal.Text);
            int games = 0;

            bool playUntilWin = !chkBench.Checked;

            for (games = 1; (playUntilWin || games <= gamesToPlay) && (curAI == null || !curAI.abort); games++)
            {

                gameBoard.NewGame();

                if (aiConfigControl1.AIConfig.ShowSteps)
                    view.InvalidateDirtyCells();

                MinesweeperAI ai = new MinesweeperAI(gameBoard, view, aiConfigControl1.AIConfig, rnd);
                curAI = ai;

                bool won = ai.PlayBoard();
                if (curAI.abort)
                {
                    break;
                }

                if (won)
                {
                    wins++;
                }
                else
                {
                    if (aiConfigControl1.AIConfig.ShowSteps)
                        view.InvalidateDirtyCells();
                }

                float percent = (float)Math.Round((decimal)(((float)wins / ((float)games) * 100f)), 2);
                int extrap20pc = (int)Math.Round((float)games * 0.2f, 0);

                int delta = wins - extrap20pc;


                string stats = string.Format("Games:  {0} / {1}    {2}   |   {3}%", wins, games, delta, percent);
                //string stats = "Games: " + games.ToString() + "     Wins: " + wins.ToString() + "  |  " + delta.ToString() + "     " + percent.ToString() + "%";
                updatelbeBench(stats);

                if (playUntilWin && won)
                    break;
            }

            games--;


            postDoWork_AI();

            view.InvalidateDirtyCells();



        }






        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            //if (gameBoard != null)
            //{
            //    gameBoard.Dispose();
            //    Application.DoEvents();
            //}

            if (curAI != null && workerThread != null && workerThread.IsAlive)
            {
                curAI.abort = true;
                while (workerThread.IsAlive)
                    Application.DoEvents();
            }
        }




        #endregion






    }


    public delegate void UIWork();
}
